/*
 * Licensed to the Apache Software Foundation (ASF) under one
 * or more contributor license agreements.  See the NOTICE file
 * distributed with this work for additional information
 * regarding copyright ownership.  The ASF licenses this file
 * to you under the Apache License, Version 2.0 (the
 * "License"); you may not use this file except in compliance
 * with the License.  You may obtain a copy of the License at
 *
 * http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing,
 * software distributed under the License is distributed on an
 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
 * KIND, either express or implied.  See the License for the
 * specific language governing permissions and limitations
 * under the License.
 */
package org.ofbiz.restaurant;

import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.sql.SQLException;
import java.util.HashMap;
import java.util.Locale;
import java.util.Map;

import javax.xml.parsers.ParserConfigurationException;

import javolution.util.FastMap;

import org.apache.fop.apps.FOPException;
import org.eclipse.birt.report.engine.api.EngineException;
import org.eclipse.birt.report.engine.api.IReportEngine;
import org.eclipse.birt.report.engine.api.IReportRunnable;

import org.ofbiz.base.location.FlexibleLocation;
import org.ofbiz.base.util.Debug;
import org.ofbiz.base.util.GeneralException;
import org.ofbiz.base.util.UtilGenerics;
import org.ofbiz.base.util.UtilMisc;
import org.ofbiz.base.util.UtilValidate;
import org.ofbiz.birt.BirtFactory;
import org.ofbiz.birt.BirtWorker;
import org.ofbiz.entity.Delegator;
import org.ofbiz.entity.GenericValue;
import org.ofbiz.security.Security;
import org.ofbiz.service.DispatchContext;
import org.ofbiz.service.LocalDispatcher;
import org.ofbiz.service.ServiceUtil;
import org.xml.sax.SAXException;

import com.lowagie.text.DocumentException;
import com.lowagie.text.pdf.PdfContentByte;
import com.lowagie.text.pdf.PdfReader;
import com.lowagie.text.pdf.PdfTemplate;
import com.lowagie.text.pdf.PdfWriter;

/**
 * Birt Services
 * 
 */
public class BirtServices {

	public final static String module = BirtServices.class.getName();

	public static int ImageResolutionFactor = 4;

	/*
	 * convert Birt to PDF file
	 */
	public static Map<String, Object> convertBirtToFile(DispatchContext ctx,
			Map<String, ? extends Object> context) {
		Map<String, Object> serviceContext = UtilMisc.makeMapWritable(context);
		Delegator delegator = ctx.getDelegator();
		LocalDispatcher dispatcher = ctx.getDispatcher();
		Security security = ctx.getSecurity();

		String birtReportLocation = (String) serviceContext
				.remove("birtReportLocation");
		Locale locale = (Locale) serviceContext.get("locale");
		Locale birtLocale = (Locale) serviceContext
				.remove(BirtWorker.BIRT_LOCALE);
		Map<String, Object> birtParameters = UtilGenerics.cast(serviceContext
				.remove(BirtWorker.BIRT_PARAMETERS));
		String birtImageDirectory = (String) serviceContext
				.remove(BirtWorker.BIRT_IMAGE_DIRECTORY);
		String birtContentType = (String) serviceContext
				.remove(BirtWorker.BIRT_CONTENT_TYPE);
		String contentType = (String) serviceContext.remove("contentType");
		String dataResourceTypeId = (String) serviceContext
				.remove("dataResourceTypeId");
		String dataTemplateTypeId = (String) serviceContext
				.remove("dataTemplateTypeId");
		String statusId = (String) serviceContext.remove("statusId");
		String mimeTypeId = (String) serviceContext.remove("mimeTypeId");
		String filePath = (String) serviceContext.remove("filePath");
		String contentTypeId = (String) serviceContext.remove("contentTypeId");
		String ownerContentId = (String) serviceContext
				.remove("ownerContentId");
		String stationaryLocation = (String) serviceContext
				.remove("stationaryLocation");

		GenericValue userLogin = (GenericValue) context.get("userLogin");
		String contentId = null;

		// check if attachment screen location passed in
		if (UtilValidate.isNotEmpty(birtReportLocation)) {
			// start processing fo pdf file
			try {
				// create the output stream for the generation
				ByteArrayOutputStream baos = new ByteArrayOutputStream();

				Map<String, Object> birtContext = FastMap.newInstance();
				if (birtLocale == null) {
					birtLocale = locale;
				}
				birtContext.put(BirtWorker.BIRT_LOCALE, birtLocale);
				if (birtParameters != null) {
					birtContext.put(BirtWorker.BIRT_PARAMETERS, birtParameters);
				}
				if (birtImageDirectory != null) {
					birtContext.put(BirtWorker.BIRT_IMAGE_DIRECTORY,
							birtImageDirectory);
				}
				if (birtContentType == null) {
					birtContentType = "application/pdf";
				}
				IReportEngine engine = BirtFactory.getReportEngine();
				HashMap<String, Object> appContext = UtilGenerics.cast(engine
						.getConfig().getAppContext());
				appContext.put("delegator", delegator);
				appContext.put("dispatcher", dispatcher);
				appContext.put("security", security);

				InputStream reportInputStream = BirtFactory
						.getReportInputStreamFromLocation(birtReportLocation);
				IReportRunnable design = engine
						.openReportDesign(reportInputStream);
				Debug.logInfo("Export report as content type:"
						+ birtContentType, module);
				BirtWorker.exportReport(design, context, birtContentType, baos);
				baos.flush();
				baos.close();

				// Write file in the file system
				File file = new File(filePath);
				File parentDir = new File(file.getParent());
				if (!parentDir.exists()) {
					parentDir.mkdirs();
				}
				FileOutputStream foStream = new FileOutputStream(file);

				// Merge pdf stationary to message core
				ByteArrayOutputStream output = new ByteArrayOutputStream();
				if (UtilValidate.isNotEmpty(stationaryLocation)) {
					stationaryLocation = FlexibleLocation.resolveLocation(
							stationaryLocation).toString();

					PdfReader readerBody = new PdfReader(baos.toByteArray());
					PdfReader readerStationary = new PdfReader(
							stationaryLocation);

					com.lowagie.text.Rectangle psize = readerBody
							.getPageSize(1);
					com.lowagie.text.Document document = new com.lowagie.text.Document(
							psize);

					PdfWriter writer = PdfWriter.getInstance(document, output);
					writer.setCompressionLevel(9);

					PdfTemplate body = writer.getImportedPage(readerBody, 1);
					PdfTemplate stationary = writer.getImportedPage(
							readerStationary, 1);
					document.open();
					PdfContentByte content = writer.getDirectContent();
					content.addTemplate(body, 0, 0);

					/*
					 * transformation matrix: with addTemplate(PdfTemplate, a,
					 * b, c, d, e, f) a b 0 c d 0 e f 1
					 */
					content.addTemplate(stationary, 1.01f, 0, 0, 1.01f, -21.5f,
							-21.5f);
					document.close();
					baos = output;
				}

				baos.writeTo(foStream);
				String fileName = file.getName();
				// Create DataResource
				GenericValue systemUserLogin = delegator.findOne("UserLogin",
						UtilMisc.toMap("userLoginId", "system"), true);
				Map<String, Object> dataResourceContext = FastMap.newInstance();
				dataResourceContext.put("dataResourceTypeId",
						dataResourceTypeId);
				dataResourceContext.put("dataTemplateTypeId",
						dataTemplateTypeId);
				dataResourceContext.put("statusId", statusId);
				dataResourceContext.put("dataResourceName", fileName);
				dataResourceContext.put("mimeTypeId", mimeTypeId);
				dataResourceContext.put("objectInfo", filePath);
				dataResourceContext.put("userLogin", systemUserLogin);
				dataResourceContext.put("skipPermissionCheck",
						context.get("skipPermissionCheck"));
				Map<String, Object> thisDataResourceResult = dispatcher
						.runSync("createDataResource", dataResourceContext);
				String dataResourceId = (String) thisDataResourceResult
						.get("dataResourceId");

				// Create Content
				Map<String, Object> contentContext = FastMap.newInstance();
				contentContext.put("contentTypeId", contentTypeId);
				contentContext.put("dataResourceId", dataResourceId);
				contentContext.put("statusId", statusId);
				contentContext.put("contentName", fileName);
				contentContext.put("mimeTypeId", mimeTypeId);
				contentContext.put("userLogin", systemUserLogin);
				contentContext.put("ownerContentId", ownerContentId);
				contentContext.put("skipPermissionCheck",
						context.get("skipPermissionCheck"));
				Map<String, Object> thisResult = dispatcher.runSync(
						"createContent", contentContext);

				contentId = (String) thisResult.get("contentId");

			} catch (GeneralException ge) {
				String errMsg = "Error rendering " + birtContentType
						+ " when converting birt file: " + ge.toString();
				Debug.logError(ge, errMsg, module);
				return ServiceUtil.returnError(errMsg);
			} catch (IOException ie) {
				String errMsg = "Error I/O rendering " + birtContentType
						+ " when converting birt file: " + ie.toString();
				Debug.logError(ie, errMsg, module);
				return ServiceUtil.returnError(errMsg);
			} catch (FOPException fe) {
				String errMsg = "Error FOP rendering " + birtContentType
						+ " when converting birt file: " + fe.toString();
				Debug.logError(fe, errMsg, module);
				return ServiceUtil.returnError(errMsg);
			} catch (SAXException se) {
				String errMsg = "Error SAX rendering " + birtContentType
						+ " when converting birt file: " + se.toString();
				Debug.logError(se, errMsg, module);
				return ServiceUtil.returnError(errMsg);
			} catch (ParserConfigurationException pe) {
				String errMsg = "Error parser rendering " + birtContentType
						+ " when converting birt file: " + pe.toString();
				Debug.logError(pe, errMsg, module);
				return ServiceUtil.returnError(errMsg);
			} catch (EngineException ee) {
				String errMsg = "Error rendering " + birtContentType
						+ " when converting birt file: " + ee.toString();
				Debug.logError(ee, errMsg, module);
				return ServiceUtil.returnError(errMsg);
			} catch (SQLException se) {
				String errMsg = "Error SQL rendering " + birtContentType
						+ " when converting birt file: " + se.toString();
				Debug.logError(se, errMsg, module);
				return ServiceUtil.returnError(errMsg);
			} catch (DocumentException e) {
				Debug.logError(e, module);
				return ServiceUtil.returnError(e.getMessage());
			}
		}
		Map<String, Object> result = FastMap.newInstance();
		result.put("contentId", contentId);
		return result;
	}
}
